﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using ConfApp.Infrastructure;
using ConfApp.Models;
using ConfApp.Services;
using ConfApp.Services.Twitter;
using Microsoft.Phone.Reactive;
using Microsoft.Phone.Shell;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
using Notification = Microsoft.Practices.Prism.Interactivity.InteractionRequest.Notification;


namespace ConfApp.ViewModels
{
    public class MainViewModel : ViewModel
    {
        private readonly InteractionRequest<Notification> submitErrorInteractionRequest;
        private readonly InteractionRequest<Notification> submitNotificationInteractionRequest;

        public IInteractionRequest SubmitErrorInteractionRequest
        {
            get { return this.submitErrorInteractionRequest; }
        }

        public IInteractionRequest SubmitNotificationInteractionRequest
        {
            get { return this.submitNotificationInteractionRequest; }
        }

        private readonly IConfDataStoreLocator _confDataStoreLocator;
        private readonly IConfDataUpdateService _confDataUpdateService;
        private readonly ITwitterStore _twitterStore;
        private readonly ITwitterUpdateService _twitterUpdateService;

        private CollectionViewSource _twittInfosViewSource;
        private CollectionViewSource _favouriteSessionInfoGroupsViewSource;
        private CollectionViewSource _nextSessionInfoGroupsViewSource;

        private readonly InteractionRequest<Notification> aboutAppInteractionRequest;
        private int selectedPanoramaIndex;
        private bool isAppBarVisible;
        private bool isSyncing;
        private DispatcherTimer timer;
        private DelegateCommand _onLoadedCommand;

        public MainViewModel(
            IConfDataStoreLocator confDataStoreLocator,
            IConfDataUpdateService confDataUpdateService,
            ITwitterStore twitterStore,
            ITwitterUpdateService twitterUpdateService,
            INavigationService navigationService)
            : base(navigationService)
        {
            PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled;

            timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0,0,1);
            timer.Tick += (s, e) =>
                              {
                                  if(During && ((int)((Time.Now-new DateTime(2000,1,1,0,0,0)).TotalSeconds)) % 60==0)
                                  {
                                      ReloadNextSessionInfos();
                                  }
                                  this.RaisePropertyChanged(() => this.BeforeOpening);
                                  this.RaisePropertyChanged(() => this.BeforeKeynote);
                                  this.RaisePropertyChanged(() => this.During);
                                  this.RaisePropertyChanged(() => this.After);
                                  this.RaisePropertyChanged(() => this.Counter);
                              };
            _confDataStoreLocator = confDataStoreLocator;
            _confDataUpdateService = confDataUpdateService;
            _twitterStore = twitterStore;
            _twitterUpdateService = twitterUpdateService;

            this.submitErrorInteractionRequest = new InteractionRequest<Microsoft.Practices.Prism.Interactivity.InteractionRequest.Notification>();
            this.submitNotificationInteractionRequest = new InteractionRequest<Microsoft.Practices.Prism.Interactivity.InteractionRequest.Notification>();

            this.AppSettingsCommand = new DelegateCommand(
                () => { this.NavigationService.Navigate(new Uri("/Views/AppSettingsView.xaml", UriKind.Relative)); },
                () => !this.IsSynchronizing);

            this.aboutAppInteractionRequest = new InteractionRequest<Notification>();
            _twittInfosViewSource = new CollectionViewSource();
            RefreshTwittsSource();
            _favouriteSessionInfoGroupsViewSource = new CollectionViewSource();
            _nextSessionInfoGroupsViewSource = new CollectionViewSource();
            this.OnLoadedCommand = new DelegateCommand(
                ()=>
                    {
                        Refresh();
                    }
                );
            this.SyncCommand = new DelegateCommand(
                () =>
                {
                    SyncData();
                },
                () => !this.IsSynchronizing);
            this.UpdateTwittsCommand = new DelegateCommand(
                () =>
                {
                    UpdateTwitts();
                },
                ()=>!this.IsSynchronizing);
            this.AboutAppCommand = new DelegateCommand(
                ()=>
                    {
                        string content =
                            "verzija 1.5.1.0" + Environment.NewLine + Environment.NewLine +
                            "Autor:" + Environment.NewLine +
                            "Srđan Božović";// +Environment.NewLine +
                            //"Zlatko Knežević" + Environment.NewLine;
                        this.aboutAppInteractionRequest.Raise(
                            new Notification
                                {
                                    Title = "Sinergija 11",
                                    Content = content
                                },
                            n => { });     
                    },
                () => !this.IsSynchronizing);
            this.SessionSelectedCommand = new DelegateCommand<SessionInfoViewModel>(
                s =>
                {
                    NavigationService.Navigate(
                        new Uri("/Views/SessionDetailsView.xaml?ID=" + s.ID, UriKind.Relative));
                });
            this.IsBeingActivated();
        }

        public bool BeforeOpening
        {
            get { return Time.Now < Time.Opening; }
        }

        public bool BeforeKeynote
        {
            get { return Time.Now < Time.Keynote; }
        }

        public bool During
        {
            get { return !BeforeKeynote && !After; }
        }

        public bool After
        {
            get { return Time.Now > Time.LastSession; }
        }

        public string Counter
        {
            get
            {
                if(BeforeOpening)
                {
                    var timeLeft = Time.Opening - Time.Now;
                    var text = new StringBuilder();
                    switch (timeLeft.Days)
                    {
                        case 61:
                        case 51:
                        case 41:
                        case 31:
                        case 21:
                        case 1:
                            text.AppendFormat("{0} dan, ", timeLeft.Days);
                            break;
                        default:
                            text.AppendFormat("{0} dana, ", timeLeft.Days);
                            break;
                    }
                    text.AppendFormat("{0:00}:{1:00}:{2:00}", timeLeft.Hours, timeLeft.Minutes, timeLeft.Seconds);
                    return text.ToString();
                }
                return "";
            }
        }

        private void UpdateTwitts()
        {
            if (this.IsSynchronizing)
            {
                return;
            }

            this.IsSynchronizing = true;
            this._twitterUpdateService
                .StartUpdating()
                .ObserveOnDispatcher()
                .Subscribe(taskSummarie => this.UpdateTwittsCompleted(
                    new List<TaskCompletedSummary>
                        {
                            taskSummarie
                        }));
        }

        private void SyncData()
        {
            if (this.IsSynchronizing)
            {
                return;
            }

            this.IsSynchronizing = true;
            this._confDataUpdateService
                .StartUpdating()
                .ObserveOnDispatcher()
                .Subscribe(taskSummarie => this.SyncCompleted(
                    new List<TaskCompletedSummary>
                        {
                            taskSummarie
                        }));
        }

        private void UpdateTwittsCompleted(IEnumerable<TaskCompletedSummary> taskSummaries)
        {
            var stringBuilder = new StringBuilder();

            var errorSummary =
                taskSummaries.FirstOrDefault(
                    s =>
                        s.Result == TaskSummaryResult.UnreachableServer ||
                        s.Result == TaskSummaryResult.AccessDenied);

            if (errorSummary != null)
            {
                stringBuilder.AppendLine(GetDescriptionForSummary(errorSummary));
                this.submitErrorInteractionRequest.Raise(
                        new Notification { Title = "Greška pri učitavanju", Content = stringBuilder.ToString() },
                        n => { });
            }
            else
            {
                foreach (var task in taskSummaries)
                {
                    stringBuilder.AppendLine(GetDescriptionForSummary(task));
                }

                if (taskSummaries.Any(t => t.Result != TaskSummaryResult.Success))
                {
                    this.submitErrorInteractionRequest.Raise(
                        new Notification { Title = "Greška pri učitavanju", Content = stringBuilder.ToString() },
                        n => { });
                }
                else
                {
                    this.submitNotificationInteractionRequest.Raise(
                        new Notification { Title = stringBuilder.ToString(), Content = null },
                        n => { });
                }
            }

            // Update the View Model status

            RefreshTwittsSource();
            this.RaisePropertyChanged(string.Empty);
            this.IsSynchronizing = false;
            this.SyncCommand.RaiseCanExecuteChanged();
            this.UpdateTwittsCommand.RaiseCanExecuteChanged();
            ////this.UpdateCommandsForSync();
        }

        private void RefreshTwittsSource()
        {
            _twittInfosViewSource.Source = _twitterStore.GetTwitts().Select(t=>
                new TwittViewModel(t)).ToList();
            this.RaisePropertyChanged(()=>this.TwittInfos);
        }

        private void SyncCompleted(IEnumerable<TaskCompletedSummary> taskSummaries)
        {
            var stringBuilder = new StringBuilder();

            var errorSummary =
                taskSummaries.FirstOrDefault(
                    s =>
                        s.Result == TaskSummaryResult.UnreachableServer ||
                        s.Result == TaskSummaryResult.AccessDenied);

            if (errorSummary != null)
            {
                stringBuilder.AppendLine(GetDescriptionForSummary(errorSummary));
                this.submitErrorInteractionRequest.Raise(
                        new Notification { Title = "Greška pri učitavanju", Content = stringBuilder.ToString() },
                        n => { });
            }
            else
            {
                foreach (var task in taskSummaries)
                {
                    stringBuilder.AppendLine(GetDescriptionForSummary(task));
                }

                if (taskSummaries.Any(t => t.Result != TaskSummaryResult.Success))
                {
                    this.submitErrorInteractionRequest.Raise(
                        new Notification { Title = "Greška pri učitavanju", Content = stringBuilder.ToString() },
                        n => { });
                }
                else
                {
                    this.submitNotificationInteractionRequest.Raise(
                        new Notification { Title = stringBuilder.ToString(), Content = null },
                        n => { });
                }
            }

            // Update the View Model status

            ReloadFavourites();
            this.RaisePropertyChanged(string.Empty);
            this.IsSynchronizing = false;
            this.SyncCommand.RaiseCanExecuteChanged();
            this.UpdateTwittsCommand.RaiseCanExecuteChanged();
            ////this.UpdateCommandsForSync();
        }

        private static string GetDescriptionForSummary(TaskCompletedSummary summary)
        {
            switch (summary.Result)
            {
                case TaskSummaryResult.Success:
                    switch (summary.Task)
                    {
                        case TwitterUpdateService.UpdatingTask:
                            return string.Format(
                                CultureInfo.InvariantCulture,
                                summary.Context=="0"?"nema novih tweet-ova" : "novih tweet-ova ({0})",
                                summary.Context);
                        case ConfDataUpdateService.SynchronizingTask:
                            return string.Format(
                                CultureInfo.InvariantCulture,
                                summary.Context.ToLowerInvariant() == "false" ? "nema novih podataka" : "novi podaci su učitani",
                                summary.Context);
                        default:
                            return string.Format(
                                CultureInfo.InvariantCulture,
                                "{0}: {1}",
                                summary.Task,
                                TaskCompletedSummaryStrings.GetDescriptionForResult(summary.Result));
                    }
                default:
                    return TaskCompletedSummaryStrings.GetDescriptionForResult(summary.Result);
            }
        }


        public ICollectionView TwittInfos
        {
            get
            {
                return _twittInfosViewSource.View;
            }
        }

        public void ReloadFavourites()
        {
            _favouriteSessionInfoGroupsViewSource.Source = GroupFavouriteSessions(_confDataStoreLocator.GetStore().GetFavouriteSessions());
            _favouriteSessionInfoGroupsViewSource.View.MoveCurrentToPrevious();
            this.RaisePropertyChanged(() => this.FavouriteSessionInfos);
        }

        public void ReloadNextSessionInfos()
        {
            _nextSessionInfoGroupsViewSource.Source = GroupNextSessions(_confDataStoreLocator.GetStore().GetNextSessions());
            _nextSessionInfoGroupsViewSource.View.MoveCurrentToPrevious();
            this.RaisePropertyChanged(() => this.NextSessionInfos);
        }

        public ICollectionView FavouriteSessionInfos
        {
            get
            {
                return _favouriteSessionInfoGroupsViewSource.View;
            }
        }

        public ICollectionView NextSessionInfos
        {
            get
            {
                return _nextSessionInfoGroupsViewSource.View;
            }
        }

        private static string SlotWithTrack(Session session)
        {
            return string.Format("[{0}] {1}", session.Track, session.Slot.ToTimeSpanString());
        }

        private List<GroupList<SessionInfoViewModel>> GroupFavouriteSessions(IEnumerable<Session> sessions)
        {
            var result = new List<GroupList<SessionInfoViewModel>>();
            var sessionInfos =
                sessions.OrderBy(s => s.Slot.Day.Date).ThenBy(s => s.Slot.ToTimeSpanString()).Select(
                    s => new SessionInfoViewModel(s, NavigationService));
            var groups = new Dictionary<string, GroupList<SessionInfoViewModel>>();

            foreach (var sessionInfo in sessionInfos)
            {
                if (groups.Count == 0)
                {
                    foreach (var slot in new string[] {"sreda", "četvrtak"})
                    {
                        var group = new GroupList<SessionInfoViewModel>(slot);
                        result.Add(group);
                        groups[slot] = group;
                    }
                }
                if (sessionInfo.Session.Slot.Day.Index == 0)
                {
                    groups["sreda"].Add(sessionInfo);
                }
                else
                {
                    groups["četvrtak"].Add(sessionInfo);
                }
            }
            return result;
        }

        private List<GroupList<SessionInfoViewModel>> GroupNextSessions(IEnumerable<Session> sessions)
        {
            var result = new List<GroupList<SessionInfoViewModel>>();
            var sessionInfos =
                sessions.OrderBy(s => s.Track.Code).Select(
                    s => new SessionInfoViewModel(s, NavigationService));
            var groups = new Dictionary<string, GroupList<SessionInfoViewModel>>();

            foreach (var sessionInfo in sessionInfos)
            {
                if (groups.Count == 0)
                {
                    foreach (var code in sessions.OrderBy(s => s.Track.Code).Select(s=>s.Track.Code).Distinct())
                    {
                        var group = new GroupList<SessionInfoViewModel>(code);
                        result.Add(group);
                        groups[code] = group;
                    }
                }
                groups[sessionInfo.TrackCode].Add(sessionInfo);
            }
            return result;
        }

        public DelegateCommand OnLoadedCommand
        {
            get { return _onLoadedCommand; }
            set { _onLoadedCommand = value; }
        }

        public DelegateCommand SyncCommand { get; set; }
        public DelegateCommand UpdateTwittsCommand { get; set; }
        public DelegateCommand AppSettingsCommand { get; set; }
        public DelegateCommand<SessionInfoViewModel> SessionSelectedCommand { get; set; }

        public IInteractionRequest AboutAppInteractionRequest
        {
            get { return this.aboutAppInteractionRequest; }
        }

        public DelegateCommand AboutAppCommand { get; set; }

        public bool IsSynchronizing
        {
            get { return this.isSyncing; }
            set
            {
                this.isSyncing = value;
                this.RaisePropertyChanged(() => this.IsSynchronizing);
            }
        }

        public bool IsAppBarVisible
        {
            get { return selectedPanoramaIndex==0; }
        }

        public int SelectedPanoramaIndex
        {
            get { return this.selectedPanoramaIndex; }

            set
            {
                this.selectedPanoramaIndex = value;
                this.RaisePropertyChanged(()=>this.SelectedPanoramaIndex);
            }
        }

        //private void HandleCurrentSectionChanged()
        //{
        //    //ICollectionView currentView = null;
        //    switch (this.SelectedPanoramaIndex)
        //    {
        //        case 0:
        //            //currentView = this.NewItems;
        //            break;
        //        case 1:
        //            //currentView = this.FavoriteItems;
        //            break;
        //        case 2:
        //            //currentView = this.ByLengthItems;
        //            break;
        //    }

        //    //if (currentView != null)
        //    //{
        //    //    this.SelectedSurveyTemplate = (SurveyTemplateViewModel)currentView.CurrentItem;
        //    //}
        //}


        public void Refresh()
        {
            ReloadFavourites();
            ReloadNextSessionInfos();
            RefreshTwittsSource();
        }

        public bool LightThemeEnabled
        {
            get
            {
                return (Visibility)Application.Current.Resources["PhoneLightThemeVisibility"] == Visibility.Visible;
            }
        }

        public ImageBrush PanoramaBackgroundImage
        {
            get
            {
                var url = LightThemeEnabled ? 
                    "/Resources/Images/light/PanoramaBackground.jpg" :
                    "/Resources/Images/dark/PanoramaBackground.jpg";
                var brush = new ImageBrush
                                {
                                    ImageSource = new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute))
                                };
                return brush;
            }
        }

        public BitmapImage AppSettingsImage
        {
            get
            {
                var url = LightThemeEnabled ?
                    "/Resources/Icons/light/appbar.feature.settings.rest.png" :
                    "/Resources/Icons/dark/appbar.feature.settings.rest.png";
                return new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute));
            }
        }

        public BitmapImage TwittsRefreshImage
        {
            get
            {
                var url = LightThemeEnabled ?
                    "/Resources/Icons/light/appbar.refresh.rest.png" :
                    "/Resources/Icons/dark/appbar.refresh.rest.png";
                return new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute));
            }
        }

        public override void IsBeingDeactivated()
        {
            Tombstoning.Save("MainPanoramaIndex", this.SelectedPanoramaIndex);
            base.IsBeingDeactivated();
            timer.Stop();
        }

        public override sealed void IsBeingActivated()
        {
            this.SelectedPanoramaIndex = Tombstoning.Load<int>("MainPanoramaIndex");
            timer.Start();
        }

        public override void IsBeingObscured(bool isLocked)
        {
            if (timer != null)
            {
                timer.Stop();
            }
        }

        public override void IsBeingUnobscured()
        {
            if (timer != null)
            {
                timer.Start();
            }
        }

    }
}